﻿using Gobang.ToolClass;
using Gobang.ToolClass.PVE;
using Sunny.UI;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;

namespace Gobang.Client.View.FrmPage
{
    public partial class GobangPage : UIPage
    {
        // 是否开始游戏
        private bool _start = false;
        // true为红色回合
        private bool _chessCheck = true;
        public bool ChessCheck
        {
            get => _chessCheck;
            set
            {
                _chessCheck = value;
                this.ExecBeginInvoke(() =>
                {
                    if (_chessCheck == _myChessCheck)
                    {
                        pictureBox3.Hide();
                        pictureBox2.Show();
                    }
                    else
                    {
                        pictureBox2.Hide();
                        pictureBox3.Show();
                    }
                });
            }
        }
        // 我为红色还是黑色
        private bool _myChessCheck = true;
        public bool MyChessCheck
        {
            get => _myChessCheck;
            set
            {
                _myChessCheck = value;
                lblPlayerColourR.Text = _myChessCheck ? "白色玩家" : "黑色玩家";
            }
        }
        // 他棋
        private bool _heChessCheck = false;
        public bool HeChessCheck
        {
            get => _heChessCheck;
            set
            {
                _heChessCheck = value;
                lblPlayerColourL.Text = _heChessCheck ? "白色玩家" : "黑色玩家";
            }
        }

        // 游戏是否结束
        private bool _isOver = false;
        /// <summary>
        /// 方块数量(15*15)
        /// </summary>
        private const int CHESSSIZE = 15;
        /// <summary>
        /// 棋子大小
        /// </summary>
        private const int PIECESIZE = 30;
        // 棋盘 棋盘二维数组分为三个值，0代表此格未落子，1代表此格为红子，-1代表黑子。
        private readonly int[,] _checkBorad;
        // 棋盘大小
        private readonly int _checkBoradSize;
        // 回合数
        private int _round = 0;
        /// <summary>
        /// 回合数
        /// </summary>
        public int Round
        {
            get => _round;
            set
            {
                _round = value;
                uiPanel5.Text = $"回合：{_round}";
            }
        }
        // 格子大小
        private readonly int _gridsSize;
        // 距桌布距离
        private readonly int _err = 35;
        // 画棋子误差
        private readonly int _chessErr;
        // 棋盘绘制初始点位，即从pictureBox左上角开始
        private readonly Point pt0;
        // 落子范围
        private const float DROPRANGE = 0.25f;
        // 落子范围
        private const float DROPRANGE2 = 1 - DROPRANGE;
        private readonly FrmGobangMain _frmGobangMain;
        private readonly ManMachine _manMachine;
        private readonly ManMachine2 _manMachine2;
        private readonly int _deskNum;
        private readonly GameTreeSearch  _gameTreeSearch;

        public GobangPage(FrmGobangMain frmGobangMain)
        {
            InitializeComponent();

            _frmGobangMain = frmGobangMain;

            _gridsSize = (pictureBox1.Width - (_err << 1)) / CHESSSIZE;
            //_err = (pictureBox1.Width - _gridsSize * CHESSSIZE) >> 1;
            pt0 = new Point(_err, _err);
            _checkBorad = new int[CHESSSIZE + 1, CHESSSIZE + 1];
            _checkBoradSize = _checkBorad.GetLength(0) * _checkBorad.GetLength(1);
            _chessErr = (PIECESIZE >> 1) - _err;

            _deskNum = _frmGobangMain._chessGameControl.DeskNum.Split('-').Last().Substring(2).ToInt32();
            if (_frmGobangMain._chessGameControl.IsManMachine)
            {

                if (_deskNum == 1)
                    _manMachine = new ManMachine(_checkBorad);
                else
                    _manMachine2 = new ManMachine2(_checkBorad);
                MyChessCheck = true;
                HeChessCheck = false;
                _gameTreeSearch = new GameTreeSearch(_checkBorad);
            }

            //pictureBox2.Hide();
            //pictureBox3.Hide();

            MyChessCheck = true;
            HeChessCheck = false;
        }
        /// <summary>
        /// 初始化对局
        /// </summary>
        private void InitializeGame()
        {
            _start = false;//对局未开始
            for (int i = 0; i < CHESSSIZE; i++)//初始化棋盘数组
            {
                for (int j = 0; j < CHESSSIZE; j++)
                {
                    _checkBorad[i, j] = 0;//把代表落子的二维数组全置为0
                }
            }
            int width = _gridsSize;//方格的宽，即棋盘两点间的距离（）
            var g = pictureBox1.CreateGraphics();//用pictureBox创建画布
            g.Clear(Color.FromArgb(210, 138, 0));//背景颜色设置
            using var pen = new Pen(Color.Black);//黑色笔刷
            using Font font = new Font(uiPanel5.Font.Name, uiPanel5.Font.SizeInPoints, uiPanel5.Font.Style);
            using SolidBrush sbrush1 = new SolidBrush(Color.Black);
            for (int line = 0; line < CHESSSIZE; line++)
            {
                float col = (_err - font.Size) / 2;
                float row = _err + _gridsSize * line + (_gridsSize - font.Size) / 2;
                g.DrawString((line + 1).ToString(), font, sbrush1, row, col);
                g.DrawString(((char)(65 + line)).ToString(), font, sbrush1, col, row);
                for (int i = 0; i < CHESSSIZE; i++)
                {
                    if (line % 2 == 0 && i % 2 == 0)//绘制偶数列和偶数行的方格
                    {
                        g.DrawRectangle(pen, i * 1 * width + pt0.X, 1 * line * width + pt0.Y, width, width);//绘制一格
                    }
                    else//绘制奇数列和奇数行的方格
                    {
                        g.DrawRectangle(pen, i * 1 * width + pt0.X, 1 * line * width + pt0.Y, width, width);
                    }
                }
            }
            g.Dispose();
        }
        /// <summary>
        /// 开始
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnStart_Click(object sender, EventArgs e)
        {
            pictureBox2.Hide();
            pictureBox3.Hide();
            InitializeGame();
            _start = true;//游戏置为开始状态
            btnStart.Text = "重新开始";//改变此按钮文本为“重新开始”
            Round = 1;//回合置1
            _isOver = false;
            _lastPoint = new Point(-1, -1);
            // 白棋先下
            ChessCheck = true;

        }
        /// <summary>
        /// 下棋
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pictureBox1_Click(object sender, EventArgs e)
        {
            //游戏开始，才可以点击
            if (!_start)
                return;

            if (_isOver)
            {
                this.ShowWarningTip("游戏已结束~");
                return;
            }
            if (ChessCheck != _myChessCheck)
            {
                this.ShowWarningTip("属于对手回合~");
                return;
            }

            Point box1Ponit = pictureBox1.PointToClient(Control.MousePosition);//设置鼠标点击后在pictureBox（即棋盘）上的坐标
            float ex = (box1Ponit.X - _err) / (float)_gridsSize;
            int integer = (int)ex;
            float dec = ex - integer;
            if (dec > DROPRANGE && dec < DROPRANGE2)
            {
                this.ShowWarningTip("点击的位置不准确哦~");
                return;
            }
            int x = integer;
            if (dec >= DROPRANGE2)
                ++x;

            ex = (box1Ponit.Y - _err) / (float)_gridsSize;
            integer = (int)ex;
            dec = ex - integer;
            if (dec > DROPRANGE && dec < DROPRANGE2)
            {
                this.ShowWarningTip("点击的位置不准确哦~");
                return;
            }
            int y = integer;
            if (dec >= DROPRANGE2)
                ++y;
            if (_checkBorad[x, y] != 0)//如果该点位有棋子
            {
                this.ShowWarningTip("请勿重复落子");
                return;
            }
            // 画棋
            DrawChess(x, y, MyChessCheck);

            //每下一个棋子，调用方法判断是否连成5个
            Point point = new Point(x, y);
            // 为true表示游戏结束
            _isOver = SuccessCheck(point, out short type);
            if (_isOver)
            {
                CreateGraphics(x, y, type);
            }

            FinalShow();

            // 机器人
            if (_frmGobangMain._chessGameControl.IsManMachine)
            {
                //Thread.Sleep(2000);
                ManMachine();
            }
        }
        private Point _lastPoint = new Point(-1, -1);
        private Brush _brushes;
        private void DrawChess(int x, int y, bool chessCheck)
        {
            Graphics g = pictureBox1.CreateGraphics();//再次创建画布
            if (_lastPoint.X != -1)
            {
                g.FillEllipse(_brushes, _lastPoint.X, _lastPoint.Y, PIECESIZE, PIECESIZE);
            }
            _brushes = Brushes.White;
            int chess = 0;
            if (chessCheck)
            {
                chess = 1;
            }
            else
            {
                chess = -1;
                _brushes = Brushes.Black;
                Round++;//黑子回合后手结束后，回合数加一
            }
            _checkBorad[x, y] = chess;

            int xz = x * _gridsSize - _chessErr;
            int yz = y * _gridsSize - _chessErr;
            g.FillEllipse(Brushes.Red, xz, yz, PIECESIZE, PIECESIZE);

            //brushes.Dispose();
            g.Dispose();

            ChessCheck = !chessCheck;
            _lastPoint.X = xz;
            _lastPoint.Y = yz;
        }

        private void CreateGraphics(int x, int y, short type)
        {
            if (type == -1)
                return;
            using Pen pen = new Pen(Color.Red, 2);
            Graphics g = pictureBox1.CreateGraphics();
            Point end = type switch
            {
                0 => new Point((x - 4) * _gridsSize + _err, y * _gridsSize + _err),
                1 => new Point((x + 4) * _gridsSize + _err, y * _gridsSize + _err),
                2 => new Point(x * _gridsSize + _err, (y - 4) * _gridsSize + _err),
                3 => new Point(x * _gridsSize + _err, (y + 4) * _gridsSize + _err),
                4 => new Point((x - 4) * _gridsSize + _err, (y - 4) * _gridsSize + _err),
                5 => new Point((x + 4) * _gridsSize + _err, (y - 4) * _gridsSize + _err),
                6 => new Point((x - 4) * _gridsSize + _err, (y + 4) * _gridsSize + _err),
                7 => new Point((x + 4) * _gridsSize + _err, (y + 4) * _gridsSize + _err),
            };
            // 还原棋子上一次的红色
            g.FillEllipse(_brushes, _lastPoint.X, _lastPoint.Y, PIECESIZE, PIECESIZE);
            g.DrawLine(pen, new Point(x * _gridsSize + _err, y * _gridsSize + _err), end);
            int color = _checkBorad[x, y];
            this.ShowSuccessDialog("决战结果", color == 1 ? "白子胜利！" : "黑子胜利！");
            g.Dispose();
        }
        /// <summary>
        /// 机器人下棋
        /// </summary>
        private void ManMachine()
        {
            //游戏开始，才可以点击
            if (_isOver)
                return;

            Seat seat = this._deskNum switch
            {
                1 => this._manMachine.BestSeat(-1, 0),
                _ => this._manMachine2.Machine() //this._manMachine2.Machine()
            };
            DrawChess(seat.X, seat.Y, HeChessCheck);
            //每下一个棋子，调用方法判断是否连成5个
            Point point = new Point(seat.X, seat.Y);
            // 为true表示游戏结束
            _isOver = SuccessCheck(point, out short type);
            if (_isOver)
            {
                CreateGraphics(seat.X, seat.Y, type);
            }
            FinalShow();
        }
        /// <summary>
        /// 判断是否五子连棋
        /// </summary>
        /// <param name="point">位置</param>
        /// <param name="type">如果五子连棋，则类别有效；
        /// 0左边；1右边；2上边；3下边；4左上；5右上；6左下；7右下；-1无效
        /// </param>
        /// <returns></returns>
        private bool SuccessCheck(Point point, out short type)
        {
            int x = point.X, y = point.Y;
            int color = _checkBorad[x, y];//当前落子颜色
            int success = 0;//连续的棋子数
            //判断棋子左边四个点位，如果左边有四个点位，且该尽头点位有同色棋子的话
            if (x - 4 >= 0 && _checkBorad[x - 4, y] == color)
            {
                for (int i = 1; i <= 3; i++)//判断中间3个棋子是否同色
                {
                    if (_checkBorad[x - i, y] == color)
                        success++; //有同色棋子则success加一        
                }
                if (success == 3)
                {
                    //success为3时，加上本身与尽头则有5个棋子，获胜
                    type = 0;
                    return true;
                }
                success = 0;
            }
            //右边判断
            if (x + 4 <= CHESSSIZE && _checkBorad[x + 4, y] == color)
            {
                for (int i = 1; i < 4; i++)
                {
                    if (_checkBorad[x + i, y] == color)
                        success++;
                }
                if (success == 3)
                {
                    type = 1;
                    return true;
                }
                success = 0;
            }
            //上边判断
            if (y - 4 >= 0 && _checkBorad[x, y - 4] == color)
            {
                for (int i = 1; i < 4; i++)
                {
                    if (_checkBorad[x, y - i] == color)
                        success++;
                }
                if (success == 3)
                {
                    type = 2;
                    return true;
                }
                success = 0;
            }
            //下边判断
            if (y + 4 <= CHESSSIZE && _checkBorad[x, y + 4] == color)
            {
                for (int i = 1; i < 4; i++)
                {
                    if (_checkBorad[x, y + i] == color)
                        success++;
                }
                if (success == 3)
                {
                    type = 3;
                    return true;
                }
                success = 0;
            }
            //左上判断
            if (x - 4 >= 0 && y - 4 >= 0 && _checkBorad[x - 4, y - 4] == color)
            {
                for (int i = 1; i < 4; i++)
                {
                    if (_checkBorad[x - i, y - i] == color)
                        success++;
                }
                if (success == 3)
                {
                    type = 4;
                    return true;
                }
                success = 0;
            }
            //右上判断
            if (x + 4 <= CHESSSIZE && y - 4 >= 0 && _checkBorad[x + 4, y - 4] == color)
            {
                for (int i = 1; i < 4; i++)
                {
                    if (_checkBorad[x + i, y - i] == color)
                        success++;
                }
                if (success == 3)
                {
                    type = 5;
                    return true;
                }
                success = 0;
            }
            //左下判断
            if (x - 4 >= 0 && y + 4 <= CHESSSIZE && _checkBorad[x - 4, y + 4] == color)
            {
                for (int i = 1; i < 4; i++)
                {
                    if (_checkBorad[x - i, y + i] == color)
                        success++;
                }
                if (success == 3)
                {
                    type = 6;
                    return true;
                }
                success = 0;
            }
            //右下判断
            if (x + 4 <= CHESSSIZE && y + 4 <= CHESSSIZE && _checkBorad[x + 4, y + 4] == color)
            {
                for (int i = 1; i < 4; i++)
                {
                    if (_checkBorad[x + i, y + i] == color)
                        success++;
                }
                if (success == 3)
                {
                    type = 7;
                    return true;
                }
                success = 0;
            }

            type = -1;
            return false;
        }
        /// <summary>
        /// 判断剩余回合数是否能五子连子
        /// </summary>
        /// <returns>
        /// -1表示剩余棋子数还富裕(不提示)；0表示棋子已下满(提示和棋，并且结束游戏)；
        /// 1表示可以下棋但不能连成五子(提示和棋不结束游戏)；2表示可以下棋至少有一个位置可以连成五子(不提示)
        /// </returns>
        private short Final()
        {
            // 剩余棋子数=棋盘大小-回合数*2
            int curResidueChess = _checkBoradSize - (Round << 1);
            if (curResidueChess == 0)
                return 0;
            // 剩余回合数
            int residueRound = 5;
            int residueChess = residueRound << 1;
            // 判断剩余棋子数
            if (curResidueChess > residueChess)
                return -1;

            int size = _checkBoradSize >> 1;
            int value;
            for (int i = 0; i < size; i++)
            {
                for (int j = 0; j < _checkBoradSize; j++)
                {
                    value = _checkBorad[i, j];
                    if (value == 0)
                    {
                        bool status = SuccessCheck(new Point(i, j), out _);// 判断该点是否能五子连棋
                        if (status)
                            goto IsHas;
                    }

                    int temp = _checkBoradSize - i;
                    value = _checkBorad[temp, j];
                    if (value == 0)
                    {
                        bool status = SuccessCheck(new Point(temp, j), out _);
                        if (status)
                            goto IsHas;
                    }
                }
            }
            return 1;
        IsHas:
            return 2;
        }
        private void FinalShow()
        {
            short f = Final();
            switch (f)
            {
                case -1:
                    break;
                case 0:
                    this.ShowInfoDialog("棋子已下满");
                    _isOver = true;
                    _start = false;
                    break;
                case 1:
                    if (ShowAskDialog("不在可以连成五子，是否考虑和棋"))
                    {
                        _isOver = true;
                        _start = false;
                    }
                    break;
                case 2:
                    break;
            }
        }

    }
}
